
#include "RenderTexture.h"
#include "D3d11Utils.h"

RenderTexture::RenderTexture(const DeviceManager* pDeviceManager, UINT width, UINT height, bool hasColorMap, DXGI_FORMAT colorMapFormat)
: mpDeviceManager(pDeviceManager), mWidth(width), mHeight(height), mColorMapFormat(colorMapFormat)
{
	BuildDepthMap();

	if( hasColorMap )
	{
		BuildColorMap();
	}

	mViewport.TopLeftX = 0;
	mViewport.TopLeftY = 0;
	mViewport.Width    = mWidth;
	mViewport.Height   = mHeight;
	mViewport.MinDepth = 0.0f;
	mViewport.MaxDepth = 1.0f;
}

void RenderTexture::Release()
{
	SAFE_RELEASE(mpColorMapSRV);
	SAFE_RELEASE(mpColorMapRTV);

	SAFE_RELEASE(mpDepthMapSRV);
	SAFE_RELEASE(mpDepthMapDSV);
}

/****************
*
* PUBLIC METHODS
*
*****************/

void RenderTexture::Begin()
{
	ID3D11RenderTargetView* renderTargets[1] = {mpColorMapRTV};
	mpDeviceManager->mpContext->OMSetRenderTargets(1, renderTargets, mpDepthMapDSV);

	mpDeviceManager->mpContext->RSSetViewports(1, &mViewport);

	if( mpColorMapRTV != NULL)
	{
		float black[] =  { 1.0f, 1.0f, 1.0f, 1.0f };
		mpDeviceManager->mpContext->ClearRenderTargetView(mpColorMapRTV, black);
	}

	mpDeviceManager->mpContext->ClearDepthStencilView(mpDepthMapDSV, D3D11_CLEAR_DEPTH, 1.0f, 0);
}

void RenderTexture::End()
{
	if( mpColorMapSRV != NULL )
	{
		mpDeviceManager->mpContext->GenerateMips(mpColorMapSRV);
	}
}

ID3D11ShaderResourceView* RenderTexture::GetColorMap()
{
	return mpColorMapSRV;
}

ID3D11ShaderResourceView* RenderTexture::GetDepthMap()
{
	return mpDepthMapSRV;
}

/****************
*
* PRIVATE METHODS
*
*****************/

void RenderTexture::BuildDepthMap()
{
	ID3D11Texture2D* depthMap = 0;

	D3D11_TEXTURE2D_DESC texDesc;
	
	texDesc.Width     = mWidth;
	texDesc.Height    = mHeight;
	texDesc.MipLevels = 1;
	texDesc.ArraySize = 1;
	texDesc.Format    = DXGI_FORMAT_R32_TYPELESS;
	texDesc.SampleDesc.Count   = 1;  
	texDesc.SampleDesc.Quality = 0;  
	texDesc.Usage          = D3D11_USAGE_DEFAULT;
	texDesc.BindFlags      = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
	texDesc.CPUAccessFlags = 0; 
	texDesc.MiscFlags      = 0;

	HR(mpDeviceManager->mpDevice->CreateTexture2D(&texDesc, 0, &depthMap));

	D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
	dsvDesc.Format = DXGI_FORMAT_D32_FLOAT;
	dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
	dsvDesc.Flags = 0;
	dsvDesc.Texture2D.MipSlice = 0;

	HR(mpDeviceManager->mpDevice->CreateDepthStencilView(depthMap, &dsvDesc, &mpDepthMapDSV));

	D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
	srvDesc.Format = DXGI_FORMAT_R32_FLOAT;
	srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
	srvDesc.Texture2D.MipLevels = texDesc.MipLevels;
	srvDesc.Texture2D.MostDetailedMip = 0;
	HR(mpDeviceManager->mpDevice->CreateShaderResourceView(depthMap, &srvDesc, &mpDepthMapSRV));

	SAFE_RELEASE(depthMap);
}

void RenderTexture::BuildColorMap()
{
	ID3D11Texture2D* colorMap = 0;

	D3D11_TEXTURE2D_DESC texDesc;
	
	texDesc.Width     = mWidth;
	texDesc.Height    = mHeight;
	texDesc.MipLevels = 0;
	texDesc.ArraySize = 1;
	texDesc.Format    = mColorMapFormat;
	texDesc.SampleDesc.Count   = 1;  
	texDesc.SampleDesc.Quality = 0;  
	texDesc.Usage          = D3D11_USAGE_DEFAULT;
	texDesc.BindFlags      = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
	texDesc.CPUAccessFlags = 0; 
	texDesc.MiscFlags      = D3D11_RESOURCE_MISC_GENERATE_MIPS;

	HR(mpDeviceManager->mpDevice->CreateTexture2D(&texDesc, 0, &colorMap));

	// Null description means to create a view to all mipmap levels using 
	// the format the texture was created with.
	HR(mpDeviceManager->mpDevice->CreateRenderTargetView(colorMap, 0, &mpColorMapRTV));
	HR(mpDeviceManager->mpDevice->CreateShaderResourceView(colorMap, 0, &mpColorMapSRV));

	// View saves a reference to the texture so we can release our reference.
	SAFE_RELEASE(colorMap);
}